#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "hal_board_cfg.h"
#include "Keyboard.h"
#include "usb_hid_keys.h"
#include "matrix.h"

byte KeyboardTaskId;
endPointDesc_t epDesc;

afAddrType_t  receiver_addr;

uint8 nwk_status = ZInvalidParameter;

uint8 keyValueBuf[8] = {0};

const cId_t InCmdList[1] = { CMD_IN };
const cId_t OutCmdList[1] = { CMD_OUT };

const SimpleDescriptionFormat_t  simpleDesc = 
{
  ENDPOINT_ID,
  PROFILE_ID,
  DEV_END_ID,
  DEV_END_VER,
  0,
  1,
  (cId_t*)InCmdList,
  1,
  (cId_t*)OutCmdList
};


void StartConfirm(uint8 status){
  if(status == ZSuccess){
    nwk_status = ZSuccess;
    
    receiver_addr.addrMode = Addr16Bit;
    receiver_addr.endPoint = ENDPOINT_ID;
    receiver_addr.addr.shortAddr = 0x0000;
  }
}
void SendDataConfirm( uint8 handle, uint8 status ){}
void BindConfirm( uint16 commandId, uint8 status ){}
void ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData){
  if(command == CMD_OUT) {
  }
}

void Keyboard_Task_Init( byte task_id ){
  
  KeyboardTaskId = task_id;

  epDesc.task_id = &KeyboardTaskId;
  epDesc.endPoint = simpleDesc.EndPoint;
  epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&simpleDesc;
  epDesc.latencyReq = noLatencyReqs;
  afRegister( &epDesc );
  // Turn off match descriptor response
  afSetMatch(epDesc.simpleDesc->EndPoint, FALSE);

  ZDO_RegisterForZDOMsg( KeyboardTaskId, NWK_addr_rsp );
  ZDO_RegisterForZDOMsg( KeyboardTaskId, Match_Desc_rsp );

  ZDOInitDevice(10);
}



uint16 Keyboard_ProcessEvent( byte task_id, uint16 events ){
 
  osal_event_hdr_t *pMsg;
  afIncomingMSGPacket_t *pMSGpkt;
  afDataConfirm_t *pDataConfirm;
  keyValues_t* pKeyValues;
  
  if ( events & SYS_EVENT_MSG )
  {
    pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );
    while ( pMsg )
    {
      switch ( pMsg->event )
      {
        case ZDO_CB_MSG:
          break;

        case AF_DATA_CONFIRM_CMD:
          pDataConfirm = (afDataConfirm_t *) pMsg;
          SendDataConfirm( pDataConfirm->transID, pDataConfirm->hdr.status );
          break;

        case AF_INCOMING_MSG_CMD:
          pMSGpkt = (afIncomingMSGPacket_t *) pMsg;
          ReceiveDataIndication( pMSGpkt->srcAddr.addr.shortAddr, pMSGpkt->clusterId,
                                 pMSGpkt->cmd.DataLength, pMSGpkt->cmd.Data);
          break;

        case ZDO_STATE_CHANGE:
          if (pMsg->status == DEV_END_DEVICE ||
              pMsg->status == DEV_ROUTER ||
              pMsg->status == DEV_ZB_COORD )
          {
            StartConfirm( ZSuccess );
          }
          else  if (pMsg->status == DEV_HOLD ||
                  pMsg->status == DEV_INIT)
          {
            StartConfirm( ZInit );
          }
          break;

        case ZDO_MATCH_DESC_RSP_SENT:
          break;
          
        case MATRIX_KEY_PRESSED_MSG:
          
          if(nwk_status == ZSuccess){
            
            pKeyValues = (keyValues_t*)pMsg;
            osal_memcpy( keyValueBuf + 2, pKeyValues->data, pKeyValues->hdr.status );
            osal_memset(keyValueBuf + 2 + pKeyValues->hdr.status, 0x00, 6 - pKeyValues->hdr.status);
            osal_msg_deallocate(pKeyValues->data );
            
            AF_DataRequest(   
                   &receiver_addr,
                   &epDesc,
                   CMD_IN,
                   8,
                   keyValueBuf,
                   0,
                   AF_DISCV_ROUTE,
                   AF_DEFAULT_RADIUS);
                
          }
          break;
  
        default:
          break;
      }
      osal_msg_deallocate( (uint8 *) pMsg );
      pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );
    }
    events ^= SYS_EVENT_MSG;
  }
  return events;
}